package studio.raptor.extractor.common.holder;

import com.google.common.base.Preconditions;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Map;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;


/**
 * Created by liuyong8 on 2017/7/20.
 */
public class ExecutorHolder {
  private static final Logger log = LoggerFactory.getLogger(ExecutorHolder.class);

  private static Map<String, ExecutorService> executors =
      new ConcurrentHashMap<String, ExecutorService>();

  private static Lock lock = new ReentrantLock();

  public static final ExecutorService createSingleThreadPool(String name) {
    lock.lock();
    Preconditions.checkArgument(!executors.containsKey(name), "%s executor exists", name);
    ExecutorService executorService =
        Executors.newSingleThreadExecutor(new NameableThreadFactory(name, true));
    executors.put(name, executorService);
    lock.unlock();
    return executorService;
  }

  public static final ExecutorService createCachedThreadPool(String name, int coreSize, int maxSize) {
    lock.lock();
    Preconditions.checkArgument(!executors.containsKey(name), "%s executor exists", name);
    ExecutorService executorService =
            new ThreadPoolExecutor(coreSize, maxSize, 30L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>(), // 线程数可伸缩
                    new NameableThreadFactory(name, true), new ThreadPoolExecutor.CallerRunsPolicy());
    executors.put(name, executorService);
    lock.unlock();
    return executorService;
  }

  private static class NameableThreadFactory implements ThreadFactory {
    private final ThreadGroup group;
    private final String namePrefix;
    private final AtomicInteger threadId;
    private final boolean isDaemon;

    public NameableThreadFactory(String name, boolean isDaemon) {
      SecurityManager s = System.getSecurityManager();
      this.group = (s != null) ? s.getThreadGroup() : Thread.currentThread().getThreadGroup();
      this.namePrefix = name;
      this.threadId = new AtomicInteger(0);
      this.isDaemon = isDaemon;
    }

    @Override
    public Thread newThread(Runnable r) {
      Thread t = new Thread(group, r, namePrefix + threadId.getAndIncrement());
      t.setDaemon(isDaemon);
      if (t.getPriority() != Thread.NORM_PRIORITY) {
        t.setPriority(Thread.NORM_PRIORITY);
      }
      return t;
    }
  }

}
